#include "fm33le0xx_fl.h"
#include "main.h"
#include "mcu_uart.h"

#define PACK_FIRST_BYTE 0xAA
#define PACK_SECOND_BYTE 0x55
#define FRAME_MIN_LEN 8
#define FRAME_MAX_LEN 1024
#define RX_BUF_SIZE FRAME_MAX_LEN
#define RX_FIFO_LENGTH (FRAME_MAX_LEN * 2)

typedef struct {
    volatile uint8_t fifo_data[RX_FIFO_LENGTH];
    volatile uint16_t start_pos;
    volatile uint16_t end_pos; // 指向下一个要写入的数
} rx_fifo_t;

static rx_fifo_t rx_fifo_data;
static volatile uint8_t tx_in_idle = 1;
static frame_recv_cb_t frame_recv_callback;

void UART1_IRQHandler(void) {
    if (UART1->ISR & UART_ISR_RXBF_Msk) { //接收中断处理
        uint16_t pos_now = rx_fifo_data.end_pos + 1;
        if (pos_now == RX_FIFO_LENGTH) {
            pos_now = 0;
        }
        // SKIP WHEN FIFO FULL
        if (pos_now == rx_fifo_data.start_pos) { 
            volatile uint8_t unused = FL_UART_ReadRXBuff(UART1);
            return ;
        }
        rx_fifo_data.fifo_data[rx_fifo_data.end_pos] = FL_UART_ReadRXBuff(UART1);
        rx_fifo_data.end_pos = pos_now;
    } else if(UART1->ISR & UART_ISR_TXSE_Msk) { // 发送中断处理
        UART1->ISR = UART_ISR_TXSE_Msk; // 清除 TXSE
        tx_in_idle = 1;
    }
}

// CRC-16 / MODBUS -> 8005H
const uint16_t crctalbeabs[] = { 
	0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 
	0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 
};
 
static uint16_t crc16tablefast(uint8_t *data, uint32_t len) {
	uint16_t crc = 0xffff; 
	uint8_t *ptr = data;
	uint32_t i;
	uint8_t ch;
 
	for (i = 0; i < len; i++) {
		ch = *ptr++;
		crc = crctalbeabs[(ch ^ crc) & 15] ^ (crc >> 4);
		crc = crctalbeabs[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
	} 
	
	return crc;
}

static uint32_t deal_uart_buffer(uint8_t* buffer, uint32_t data_length) {
    uint8_t* deal_ptr = (uint8_t *)buffer;
    uint32_t packet_len = 0;

    while (data_length > 1) {
		if(deal_ptr[0] == PACK_FIRST_BYTE && deal_ptr[1] == PACK_SECOND_BYTE) {
            break ;
        }
        deal_ptr += 1;
        data_length -= 1;
    }
    if (data_length < FRAME_MIN_LEN) {
        goto exit;
    }
    packet_len = (deal_ptr[2] << 8) | deal_ptr[3];
    if (packet_len > RX_BUF_SIZE || packet_len < FRAME_MIN_LEN) {
        // skip error length, find next head
        packet_len = 2;
        goto exit;
    }
     if (data_length < packet_len) {
        packet_len = 0;
        goto exit;
    }

    if (crc16tablefast(deal_ptr, packet_len - 2) != ((deal_ptr[packet_len - 2] << 8) | deal_ptr[packet_len - 1])) {
        goto exit;
    }

    if (frame_recv_callback) {
        uint32_t cmd = (deal_ptr[4] << 8) | deal_ptr[5];
        uint8_t* data_ptr = deal_ptr + 6;
        uint8_t* data_align_32_ptr = data_ptr - (uint32_t)data_ptr % 4;
        if (data_align_32_ptr != data_ptr) {
            memmove(data_align_32_ptr, data_ptr, packet_len - FRAME_MIN_LEN);
        } 
        frame_recv_callback(cmd, data_align_32_ptr, packet_len - FRAME_MIN_LEN);
    }

exit:
    deal_ptr += packet_len;
    return deal_ptr - buffer;
}

void mcu_uart_init(frame_recv_cb_t recv_cb) {
    FL_UART_ClearFlag_TXShiftBuffEmpty(UART1);
    FL_UART_EnableIT_TXShiftBuffEmpty(UART1);     // 使能发送中断
    FL_UART_ClearFlag_RXBuffFull(UART1);
    FL_UART_EnableIT_RXBuffFull(UART1);           // 使能接收中断
    FL_UART_EnableTX(UART1);
    FL_UART_EnableRX(UART1);

    rx_fifo_data.start_pos = 0;
    rx_fifo_data.end_pos = 0;

    tx_in_idle = 1;

    frame_recv_callback = recv_cb;
}

void mcu_uart_deinit() {

}

void mcu_uart_write(const uint8_t* buffer, uint32_t length) {
    while (tx_in_idle == 0);
    tx_in_idle = 0;
    FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};
    DMA_ConfigStruct.memoryAddress = (uint32_t)buffer;
    DMA_ConfigStruct.transmissionCount = length - 1;
    FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, FL_DMA_CHANNEL_6);
}

void mcu_deal_rx_fifo_data() {
    static uint8_t buffer_stash[RX_BUF_SIZE];
    static uint16_t buffer_total_len = 0;

    uint16_t num = 0;
    uint16_t used_size;
    
    while (rx_fifo_data.start_pos != rx_fifo_data.end_pos) {
        uint16_t end_pos = rx_fifo_data.end_pos;
        if (end_pos < rx_fifo_data.start_pos) {
            num = RX_FIFO_LENGTH - rx_fifo_data.start_pos;
        } else {
            num = end_pos - rx_fifo_data.start_pos;
        }
        if (buffer_total_len + num > RX_BUF_SIZE) {
            num = RX_BUF_SIZE - buffer_total_len;
        }
        memcpy(buffer_stash + buffer_total_len, (void *)(rx_fifo_data.fifo_data + rx_fifo_data.start_pos), num);
        buffer_total_len += num;
        
        if (rx_fifo_data.start_pos + num >= RX_FIFO_LENGTH) {
            rx_fifo_data.start_pos = rx_fifo_data.start_pos + num - RX_FIFO_LENGTH;
        } else {
            rx_fifo_data.start_pos += num;
        }

        do {
            used_size = deal_uart_buffer(buffer_stash, buffer_total_len);
            buffer_total_len -= used_size;
            memmove(buffer_stash, buffer_stash + used_size, buffer_total_len);
        } while ((buffer_total_len > 1 && used_size != 0));
    }
}

void mcu_write_bytes(uint16_t cmd, const uint8_t* frame, uint32_t len) {
    static uint8_t out_buf[FRAME_MAX_LEN];
    uint32_t out_len = FRAME_MIN_LEN + len;
    if (out_len > FRAME_MAX_LEN) {
        return ;
    }
    // 等待DMA发送完成
    while (tx_in_idle == 0);

    out_buf[0] = PACK_FIRST_BYTE;
    out_buf[1] = PACK_SECOND_BYTE;
    out_buf[2] = out_len >> 8; 
    out_buf[3] = out_len & 0xff;
    out_buf[4] = cmd >> 8;
    out_buf[5] = cmd & 0xff;
    memcpy(&out_buf[6], frame, len);
    uint16_t crc16_result = crc16tablefast(out_buf, 6 + len);
    out_buf[5 + len + 1] = crc16_result >> 8;
    out_buf[5 + len + 2] = crc16_result & 0xff;
    mcu_uart_write(out_buf, out_len);
}
